using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.IO;
using Ltf.Remoting.Settings;
using System.Runtime.InteropServices;

namespace Ltf.Remoting.TFAccess
{
	public class TFDifRepository : IDifRepository
	{
		[DllImport("imagehlp.dll")]
		public static extern int MapFileAndCheckSumA(string fileName, ref int headerSum, ref int checkSum);

		private VersionControlServer vcServer;
		private string tempPath;

		Dictionary<string, Item> itemCache=null;
		Dictionary<int, ExtendedItem> extItemCache=null;

		public void PrepCache(string fsPath)
		{
			itemCache = new Dictionary<string, Item>();
			extItemCache = new Dictionary<int, ExtendedItem>();
			VersionSpec vs = VersionSpec.Latest;
			if (version > 0)
				vs = new ChangesetVersionSpec(version);
			ItemSet items = vcServer.GetItems(fsPath, vs, RecursionType.Full);
			foreach (Item item in items.Items)
			{
				itemCache.Add(item.ServerItem, item);
			}
			//ItemSpec itemSpec = new ItemSpec(fsPath, RecursionType.Full);
			//ExtendedItem[] extItems = ws.GetExtendedItems(new ItemSpec[] {itemSpec},DeletedState.NonDeleted, ItemType.Any)[0];
			//foreach (ExtendedItem extItem in extItems)
			//{
			//  if (extItem.LocalItem!=null)
			//    extItemCache.Add(extItem.ItemId, extItem);
			//}
		}


		public TFDifRepository(VersionControlServer vcServer, string tempPath)
		{
			this.vcServer = vcServer;
			this.tempPath = tempPath;
		}

		public TFDifRepository(VersionControlServer vcServer, int version, string tempPath)
		{
			this.vcServer = vcServer;
			this.tempPath = tempPath;
			this.version = version;
		}


		private int version = 0;

		public int Version
		{
			get { return version; }
			set { version = value; }
		}
		private int deletionId;

		public int DeletionId
		{
			get { return deletionId; }
			set { deletionId = value; }
		}
	
		#region IDifRepository Members

		public bool FolderExists(string path)
		{
			try
			{
				Item i = GetItem(path);
				return (i.ItemType == ItemType.Folder);
			}
			catch
			{
				return false;
			}
		}

		public bool FileExists(string path)
		{
			try
			{
				Item i = GetItem(path);
				return (i.ItemType == ItemType.File);
			}
			catch
			{
				return false;
			}
		}

		public bool FileOrFolderExists(string path)
		{
			try
			{
				Item i = GetItem(path);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public IEnumerable<string> GetFolderItems(string path, DifItemType itemType)
		{
			if (FolderExists(path))
			{
				if (version > 0)
				{
					List<int> itemsList = new List<int>();
					foreach (Item item in vcServer.GetItems(path,new ChangesetVersionSpec(version),RecursionType.OneLevel,DeletedState.Any,ItemType.Any).Items)
					{
						if (item.ServerItem!=path)
						{
							if (item.DeletionId==0 &&  itemType == DifItemType.Any
								|| (itemType == DifItemType.File && item.ItemType == ItemType.File)
								|| (itemType == DifItemType.Folder && item.ItemType == ItemType.Folder))
							{
								yield return item.ServerItem;
							}
						}
					}
				}
				else
				{
					foreach (Item item in vcServer.GetItems(path + "/*").Items)
					{
						if (item.DeletionId == 0 && itemType == DifItemType.Any
							|| (itemType == DifItemType.File && item.ItemType == ItemType.File)
							|| (itemType == DifItemType.Folder && item.ItemType == ItemType.Folder))
						{
							yield return item.ServerItem;
						}
					}
				}
			}
			else
			{
		//		throw new System.IO.DirectoryNotFoundException(string.Format("Folder {0} does not exist.", path));
			}
		}


		public System.IO.Stream GetFileItemStream(string path)
		{
			Item item=GetItem(path);
			string downloadPath = string.Format("{0}/{1}", tempPath, Path.GetFileName(path));

			//try
			//{
			//  string fsPath = extItemCache[item.ItemId].LocalItem;
			//  string localcopy = LizardFileAccess.GetLTFLocalCacheFileName(fsPath);
			//  LizardFileInfo lfi = LizardFileAccess.GetLizardFileInfo(fsPath);
			//  // check if the version we're interested in happens to match the cache
			//  if (lfi != null && lfi.LocalVersion == item.ChangesetId)
			//  {
			//    // if it exists, then use it!
			//    if (File.Exists(localcopy))
			//    {
			//      return File.OpenRead(localcopy);
			//    }
			//    // seeing as its the local one we're interested in, we may as well save it in the right place
			//    downloadPath = localcopy;
			//  }
			//}
			//catch
			//{ }

			item.DownloadFile(downloadPath);
			byte[] bytes = File.ReadAllBytes(downloadPath);
			File.Delete(downloadPath);
			MemoryStream ms = new MemoryStream(bytes);
			ms.Position = 0;
			return ms;
		}

		public int GetFileChecksum(string path)
		{
			int hs1 = 0, cs1 = 0;
			Item item = GetItem(path);
			string downloadPath = string.Format("{0}/{1}", tempPath, Path.GetFileName(path));
			string localcopy = LizardFileAccess.GetLTFLocalCacheFileName(path);
			try
			{
				// we might already have it!
				LizardFileInfo lfi = LizardFileAccess.GetLizardFileInfo(path);
				// check if the version we're interested in happens to match the cache
				if (lfi != null && lfi.LocalVersion == item.ChangesetId)
				{
					// if we don't have a local copy we won't have a checksum for it...
					if (File.Exists(localcopy))
					{
						return lfi.LocalVersionChecksum;
					}
					// seeing as its the local one we're interested in, we may as well save it in the right place
					downloadPath = localcopy;
				}
			}
			catch
			{ }


			item.DownloadFile(downloadPath);
			int fh1 = MapFileAndCheckSumA(path, ref hs1, ref cs1);
			File.Delete(downloadPath);
			return cs1;
		}


		private Item GetItem(string path)
		{
			path = path.Replace('\\', '/');
			if (itemCache != null && itemCache.ContainsKey(path))
				return itemCache[path];

			string name;
			int v;

			LizardFileAccess.GetNameAndVersionFromPath(path, out name, out v);

			if (version > 0)
			{
				Item item;
				try
				{
					item = vcServer.GetItem(name, new ChangesetVersionSpec(version), deletionId);
				}
				catch (Exception ex)
				{
					// maybe it had a different name back then?
					Item item2 = vcServer.GetItem(name,VersionSpec.Latest, deletionId);

					item = vcServer.GetItem(item2.ItemId, version);
				}
				return item;
				}
			else
			{
				Item item = vcServer.GetItem(name, LatestVersionSpec.Latest, deletionId);
				return item;
			}
		}

		public bool LastItemHasPotentialConflict
		{ get { return false; } }

		public int GetQuickItemCount(TFSettings settings, string path)
		{
			VersionSpec vs;
			if (version==0)
				vs=new ChangesetVersionSpec(vcServer.GetLatestChangesetId());
		  else
				vs=new ChangesetVersionSpec(version);
			Item[] items = vcServer.GetItems(path, vs, RecursionType.Full, (deletionId==0)?DeletedState.NonDeleted:DeletedState.Any, ItemType.File).Items;
			return items.Length;
		}

		public string GetVersionQualifiedPath(string path)
		{
			return LizardFileAccess.SetPathVersion(path, version);
		}
		#endregion
	}
}
